this article was contributed by chris copenhaver.
the animated bitmap button is a class which allows you to have 256 color based animations
which act as buttons.
the animated bitmap button class (canibutton) started quite innocently. my office
mate and i were playing with standard bitmap buttons and wanted to create one using 256
color device independent bitmaps (dib). a class was created called cbitmapbuttonex
which worked exactly like a cbitmapbutton except for it worked with dibs. the first
button we created was a "globe" button which looked really good. there was
a long standing joke about making the world spin... from this joke was born
canibutton class!
we want a button which will act exactly like a regular windows button, but not look like
one. the button should animate when it is enabled and be still when it is
disabled. normal windows buttons have four states: "up", "down",
"focused", and "disabled". for the "up",
"down", and "focused" states, the button will be animating. all
of these states are loaded with one bitmap. the bitmap must be in a very specific
format. there must be three rows in the bitmap. one row for each of the three
states which must be represented. the first row of images will be the "up"
state, followed by the "focused" state and then the "down"
state. the number of columns will depend on the number of frames of animation.
the bitmap for the "disabled" state will be considerably smaller, since it will
only contain one image. when completed, the bitmabs will be similar to the ones
below.
"up", "focused", and "down"
bitmap
disabled bitmap.
with five frames of animation.
here is an actual example of an american flag button. notice that the first row is
the "up" state. the second row is the focused state. it is
exactly like the top row, except it has a red border around the flag to show that it has
the input focus. the third row is the "sown" state. it is exactly
like the middle row, except the shadow is removed and the flag is moved down and to the
right a little to give the impression that the button has been pressed...
using the canibutton class is simple. first you will need to add the canibutton.h
(cpp) and the cdib.h (cpp) files to your project. you might want to rebuild your
class wizard database so that it knows about the new classes in your project. next,
add an owner drawn button to a dialog. using class wizard, add a member variable for
the button using the canibutton class as the variable type. in the dialog's
oninitdialog method, add a call to the button's autoload method, and the button will be
created! you will also want to handle the on_wm_palettechanged and
on_wm_querynewpalette messages inside of the dialog to do some palette work. take a
look at the example application's code to see how this is done.
bool cbtntestdlg::oninitdialog()
{
// initialize all of our canibuttons before we
// do anything else!
m_btnglobe.autoload(idc_globe2, // resource id
this, // parent window
idb_globe_button, // main bitmap resource id
idb_globe_disabled, // disabled bitmap resource id
10, // 10 frames per second
0, // calculate number of frames
false, // do not stretch to fit
true, // replace face color
idc_plane_cursor); // cursor resourse id
cdialog::oninitdialog();
// set the icon for this dialog. the framework does this automatically
// when the application's main window is not a dialog
seticon(m_hicon, true); // set big icon
seticon(m_hicon, false); // set small icon
return true; // return true unless you set the focus to a control
}
void cbtntestdlg::onpalettechanged(cwnd* pfocuswnd)
{
//
// if this window is not the window getting focus,
// redraw the anibuttons...
//
if(pfocuswnd != this)
{
// a simple call to invalidate will cause the
// button to be redrawn and it's palette realized.
m_btnglobe.invalidate();
}
}
bool cbtntestdlg::onquerynewpalette()
{
// make sure the anibutton's palette
// becomes the foreground palette.
m_btnglobe.realizepalette();
return cdialog::onquerynewpalette();
}
canibutton::autoload
bool canibutton::autoload(uint nid,
cwnd* pparent,
uint nbitmapid,
uint ndisabledid,
uint nframespersecond,
uint nnumframes = 0,
bool bstretchtofit = false,
bool bchangefacecolor = true,
uint ncursorid = 0);
bool canibutton::autoload(uint nid,
cwnd* pparent,
const char* szfilename,
const char* szdisabledfilename,
uint nframespersecond,
uint nnumframes,
bool bstretchtofit,
bool bchangefacecolor,
uint ncursorid);
return value
nonzero if successful; otherwise 0.
parameters
nid the button's control id.
pparent pointer to the object that owns the button.
nbitmapid the resource id of the buttons main
bitmap for the "up", "down", and
"focused" states. required.
ndisabledid the resource id of the button's bitmap for the "disabled" state.
szfilename the filename of the buttons main
bitmap for the "up", "down", and
"focussed" states. required.
szdisabledfilename the filename of the button's bitmap for the "disabled" state.
nframespersecond the number of animation frames to cycle through each second.
nnumframes the total number of frames that are in
the animation. if this argument
is set to 0, the number of frames will be determined by comparing
the width of the disabled bitmap with the width of the main bitmap.
example: if the disabled bitmap is 50 pixels wide and the main bitmap
is 250 pixels wide, 250 / 50 = 5 frames of animation...
bstretchtofit if this flag is set to true, the
bitmap will be stretched to fit the size
of the button. a setting of false will center the bitmap on the button.
bchangefacecolor if this flag is set to true, all
pixels with the same color as the
first pixel in the bitmap will be changed to match the windows
3-d face color. this makes the button look transparent. a
setting of false will not modify any of the pixels.
ncursorid the resource id of the cursor to be
displayed when the cursor is moved
over the button itself. a setting of 0 means the cursor will not change.
download demo project - 176 kb
date posted: september 6, 1998